macos: add more aggressive clip to transparent subview
authorChristian Hergert <chergert@redhat.com>
Fri, 30 Oct 2020 02:37:27 +0000 (19:37 -0700)
committerChristian Hergert <chergert@redhat.com>
Fri, 30 Oct 2020 02:41:21 +0000 (19:41 -0700)
The Cairo implementation for the Macos backend uses a toplevel
window with full transparency and a series of NSView to create opaque
regions. This improves compositor performance because it allows the
display server to avoid costly blends.

However, we want to ensure we clip better when exposing the
transparent region so that we only expose the shadows/corners as
necessary.

gdk/macos/GdkMacosCairoSubview.c
gdk/macos/GdkMacosCairoSubview.h
gdk/macos/GdkMacosCairoView.c

index 425b52ac788c8c8311301c5966cce4ab8599eb20..e52acdf168fa74632e5dc5daf21f26591e359d7c 100644 (file)
 
 @implementation GdkMacosCairoSubview
 
+-(void)dealloc
+{
+  g_clear_pointer (&self->clip, cairo_region_destroy);
+  [super dealloc];
+}
+
 -(BOOL)isOpaque
 {
   return _isOpaque;
   cr = cairo_create (dest);
   cairo_translate (cr, -abs_bounds.origin.x, -abs_bounds.origin.y);
 
+  /* Apply the clip if provided one */
+  if (self->clip != NULL)
+    {
+      cairo_rectangle_int_t area;
+
+      n_rects = cairo_region_num_rectangles (self->clip);
+      for (guint i = 0; i < n_rects; i++)
+        {
+          cairo_region_get_rectangle (self->clip, i, &area);
+          cairo_rectangle (cr, area.x, area.y, area.width, area.height);
+        }
+
+      cairo_clip (cr);
+    }
+
   /* Clip the cairo context based on the rectangles to be drawn
    * within the bounding box :rect.
    */
   self->_isOpaque = opaque;
 }
 
+-(void)setClip:(cairo_region_t*)region
+{
+  if (region != self->clip)
+    {
+      g_clear_pointer (&self->clip, cairo_region_destroy);
+      if (region != NULL)
+        self->clip = cairo_region_reference (region);
+    }
+}
+
 @end
index 925534756614973ceed3a793354c525d819d02cd..5eae734f8f58416009987665f833134d7cb08227 100644 (file)
 {
   BOOL             _isOpaque;
   cairo_surface_t *cairoSurface;
+  cairo_region_t  *clip;
 }
 
 -(void)setOpaque:(BOOL)opaque;
 -(void)setCairoSurface:(cairo_surface_t *)cairoSurface
             withDamage:(cairo_region_t *)region;
+-(void)setClip:(cairo_region_t*)region;
 
 @end
index 2f8248891206912427529403cffb1528b36cb05e..81ac8af6a3ac41f3e15cdacf61fad293032fbf40 100644 (file)
@@ -78,6 +78,7 @@
 
 -(void)setOpaqueRegion:(cairo_region_t *)region
 {
+  cairo_region_t *transparent_clip;
   NSRect abs_bounds;
   guint n_rects;
 
   abs_bounds = [self convertRect:[self bounds] toView:nil];
   n_rects = cairo_region_num_rectangles (region);
 
+  /* First, we create a clip region for the transparent region to use so that
+   * we dont end up exposing too much other than the corners on CSD.
+   */
+  transparent_clip = cairo_region_create_rectangle (&(cairo_rectangle_int_t) {
+    abs_bounds.origin.x, abs_bounds.origin.y,
+    abs_bounds.size.width, abs_bounds.size.height
+  });
+  cairo_region_subtract (transparent_clip, region);
+  [(GdkMacosCairoSubview *)self->transparent setClip:transparent_clip];
+  cairo_region_destroy (transparent_clip);
+
   /* The common case (at least for opaque windows and CSD) is that we will
    * have either one or two opaque rectangles. If we detect that the same
    * number of them are available as the previous, we can just resize the